#pragma once
#include <iostream>
#include <unordered_map>
#include "../comm/Util.hpp"
#include "../comm/Log.hpp"
#include "../comm/ManageUser.hpp"


namespace ns_model
{
    using namespace ns_util;
    using namespace ns_log;
    using namespace ns_usr;


    const std::string QUESTIONS_BANK = "./question_bank/";
    const std::string QUESTION_HEADER = "/header.cc";
    const std::string QUESTION_TAIL = "/tail.cc";
    const std::string QUESTION_DESC = "/desc.txt";
    const std::string QUESTIONS_LIST = "list.txt";
    const std::string SEP = " ";

    class Question
    {
    public:
        std::string number;  // 题目编号
        std::string name;    // 题目名
        std::string star;    // 难度
        size_t cpu_limit;    // 题目时间限制
        size_t mem_limit;    // 题目空间限制
        std::string desc;    // 题目的描述
        std::string headers; // 给用户提供的题目预设
        std::string tail;    // 为判题程序提供的测试用例
        std::string code;    // headers + tail 拼接起来给判题程序编译运行
    };


    class Model
    {
    public:

        //问题库
        std::unordered_map<std::string, Question> questions;
        //用户管理
        ManageUser _mgusr;


    private:
        // 加载每一个题目到内存
        void Load()
        {
            std::vector<std::string> quest_v;
            // 从文件中获取每一道题
            FileUtil::ReadLineFile(quest_v, QUESTIONS_BANK + QUESTIONS_LIST);
            int n = quest_v.size();
            if (n == 0)
            {
                LOG(WARNING) << "题库为空，或读取题库失败" << "\n";
            }
            // 加载到内存
            for (int i = 0; i < n; i++)
            {
                // 1 求最大值 简单 1 30000
                Question q;
                std::vector<std::string> v;
                if (!StrUtil::SplitString(v, quest_v[i], SEP))
                {
                    LOG(ERROR) << "题库切字符,切空" << "\n";
                    continue;
                }
                if (v.size() != 5)
                {
                    LOG(ERROR) << "题库格式问题,出现有题目加载失败" << "\n";
                    continue;
                }
                // 构建题目
                q.number = v[0];
                q.name = v[1];
                q.star = v[2];
                q.cpu_limit = atoi(v[3].c_str());
                q.mem_limit = atoi(v[4].c_str());
                FileUtil::ReadFile(q.desc, QUESTIONS_BANK + q.number + QUESTION_DESC);
                FileUtil::ReadFile(q.headers, QUESTIONS_BANK + q.number + QUESTION_HEADER);
                FileUtil::ReadFile(q.tail, QUESTIONS_BANK + q.number + QUESTION_TAIL);
                // 加载内存
                questions.insert({q.number, q});
            }
        }

    public:
        Model()
        {
            Load();
        }
        ~Model() {}

        // v:输出型参数，输出获取的题目列表
        // Sort:是否需要按编号排升序(默认true排序)
        bool GetQuestions(std::vector<Question> &v, bool Sort = true)
        {
            for (auto it : questions)
            {
                v.push_back(it.second);
            }
            if (v.size() == 0)
            {
                LOG(WARNING) << "获取题目列表为空" << "\n";
                return false;
            }
            sort(v.begin(), v.end(), [](const Question &q1, const Question &q2)
                 { return atoi(q1.number.c_str()) < atoi(q2.number.c_str()); });
            return true;
        }

        // q:输出型参数，输出获取的题目信息
        // number:获取题目的题目编号
        bool GetOneQuestion(Question &q, const std::string &number)
        {
            auto it = questions.find(number);
            if (it == questions.end())
            {
                LOG(WARNING) << "获取" << number << "号题目失败" << "\n";
                return false;
            }
            q = it->second;
            return true;
        }
    };

}
